﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Model.Context;
using Ones.Dal.Repository.Interfaces;

namespace Ones.Dal.Repository.Impl
{
    public abstract class AbstractDao<T> : IDao<T> where T : class
    {
        protected OnlineNewsEditorialDataContext _ctx;

        public AbstractDao() : this(new OnlineNewsEditorialDataContext())
        {
        }

        public AbstractDao(OnlineNewsEditorialDataContext dc)
        {
            _ctx = dc;
        }
        
        public OnlineNewsEditorialDataContext Ctx
        {
            get
            {
                return this._ctx;
            }
            set
            {
                this._ctx = value;
            }
        }

        public virtual bool
        create(T t)
        {
            try
            {
                _ctx.GetTable<T>().InsertOnSubmit(t);
                _ctx.SubmitChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        
        public virtual bool
        update(T t)
        {
            try
            {
                //var currentT = getById("maybe we should using method that find out id field of t, then return value");
                //currentT = t;
                _ctx.SubmitChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        
        public bool
        delete(object id)
        {
            try
            {
                _ctx.GetTable<T>().DeleteOnSubmit(getById(id));
                _ctx.SubmitChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        
        public List<T>
        getAll()
        {
            try
            {
                return _ctx.GetTable<T>().ToList<T>();
            }
            catch (Exception)
            {
                return null;
            }
        }
        
        public abstract T
        getById(object id);

        public List<T>
        getMultiple(Expression<Func<T, bool>> whereCondition)
        {
            try
            {
                return _ctx.GetTable<T>().Where(whereCondition).ToList();
            }
            catch (Exception)
            {
                return null;
            }
        }

        public T
        getSingle(Expression<Func<T, bool>> whereCondition)
        {
            return _ctx.GetTable<T>().Where(whereCondition).SingleOrDefault();
        }

        #region Utils
        
        /// <summary>
        /// http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/
        /// </summary>
        public Expression<Func<TElement, bool>>
        BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            if (null == valueSelector)
                throw new ArgumentNullException("valueSelector");
            if (null == values)
                throw new ArgumentNullException("values");
            
            ParameterExpression p = valueSelector.Parameters.Single();
            if (!values.Any())
            {
                return e => false;
            }
            
            var equals =
                values.Select(
                    value => (Expression)Expression.Equal(
                        valueSelector.Body, Expression.Constant(value, typeof(TValue))));
            
            var body = equals.Aggregate(Expression.Or);
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }
        
        #endregion
    }
}

//public override bool
//update(AdvertisementContact advContact)
//{
//    try
//    {
//        var curr = getById();

//        _ctx.SubmitChanges();
//        return true;
//    }
//    catch (Exception)
//    {
//        return false;
//    }
//}